#include "CorelSpyAPI.h"

extern BOOL GlobInit();
extern CCorelSpyAPIProxy *g_pcAPIProxy;

#define ATTACH(x) DetourAttach(&(PVOID&)True##x, Corel##x)
#define DETACH(x) DetourDetach(&(PVOID&)True##x, Corel##x)

extern BOOL GlobInit();

VOID (WINAPI * TrueOutputDebugStringA)(LPCSTR lpOutputString)  = OutputDebugStringA;
VOID (WINAPI * TrueOutputDebugStringW)(LPCWSTR lpOutputString) = OutputDebugStringW;
LRESULT (WINAPI *TrueSendMessageA)(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) = SendMessageA;
LRESULT (WINAPI *TrueSendMessageW)(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) = SendMessageW;
BOOL (WINAPI *TruePostMessageA)(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) = PostMessageA;
BOOL (WINAPI *TruePostMessageW)(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) = PostMessageW;
long (WINAPI *TrueBroadcastSystemMessageA)(DWORD flags, LPDWORD lpInfo, UINT Msg, WPARAM wParam, LPARAM lParam) = BroadcastSystemMessageA;
long (WINAPI *TrueBroadcastSystemMessageW)(DWORD flags, LPDWORD lpInfo, UINT Msg, WPARAM wParam, LPARAM lParam) = BroadcastSystemMessageW;
long (WINAPI *TrueBroadcastSystemMessageExA)(DWORD flags,LPDWORD lpInfo, UINT Msg, WPARAM wParam, LPARAM lParam, PBSMINFO pbsmInfo) = BroadcastSystemMessageExA;
long (WINAPI *TrueBroadcastSystemMessageExW)(DWORD flags,LPDWORD lpInfo, UINT Msg, WPARAM wParam, LPARAM lParam, PBSMINFO pbsmInfo) = BroadcastSystemMessageExW;
HMODULE (WINAPI *TrueLoadLibraryA)(LPCSTR lpLibFileName) = LoadLibraryA;
HMODULE (WINAPI *TrueLoadLibraryW)(LPCWSTR lpLibFileName) = LoadLibraryW;
HMODULE (WINAPI *TrueLoadLibraryExA)(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) = LoadLibraryExA;
HMODULE (WINAPI *TrueLoadLibraryExW)(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) = LoadLibraryExW;
int (WINAPI *TrueMultiByteToWideChar)(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte, LPWSTR lpWideCharStr, int cchWideChar) = MultiByteToWideChar;
int (WINAPI *TrueWideCharToMultiByte)(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar) = WideCharToMultiByte;
PFN_RtlMultiByteToUnicodeN TrueRtlMultiByteToUnicodeN = NULL;
PFN_RtlUnicodeToMultiByteN TrueRtlUnicodeToMultiByteN = NULL;
PFN_RtlMultiByteToUnicodeSize TrueRtlMultiByteToUnicodeSize = NULL;
PFN_RtlUnicodeToMultiByteSize TrueRtlUnicodeToMultiByteSize = NULL;


HRESULT DetourAttach()
{
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());

    //ATTACH(OutputDebugStringA);
    //ATTACH(OutputDebugStringW);
    //ATTACH(SendMessageA);
    //ATTACH(SendMessageW);
    //ATTACH(PostMessageA);
    //ATTACH(PostMessageW);
    //ATTACH(LoadLibraryA);
    //ATTACH(LoadLibraryW);
    //ATTACH(LoadLibraryExA);
    ATTACH(LoadLibraryExW);
    //ATTACH(MultiByteToWideChar);
    ATTACH(WideCharToMultiByte);

    //HMODULE t_hModule = GetModuleHandle(_T("ntdll.dll"));
    //TrueRtlMultiByteToUnicodeN = (PFN_RtlMultiByteToUnicodeN)GetProcAddress(t_hModule, "RtlMultiByteToUnicodeN");
    //ATTACH(RtlMultiByteToUnicodeN);

    //TrueRtlUnicodeToMultiByteN = (PFN_RtlUnicodeToMultiByteN)GetProcAddress(t_hModule, "RtlUnicodeToMultiByteN");
    //ATTACH(RtlUnicodeToMultiByteN);

    //TrueRtlMultiByteToUnicodeSize = (PFN_RtlMultiByteToUnicodeSize)GetProcAddress(t_hModule, "RtlMultiByteToUnicodeSize");
    //TrueRtlUnicodeToMultiByteSize = (PFN_RtlUnicodeToMultiByteSize)GetProcAddress(t_hModule, "RtlUnicodeToMultiByteSize");

    DetourTransactionCommit();

    return S_OK;
}

HRESULT DetourDetach()
{
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());

    //DETACH(OutputDebugStringA);
    //DETACH(OutputDebugStringW);
    //DETACH(SendMessageA);
    //DETACH(SendMessageW);
    //DETACH(PostMessageA);
    //DETACH(PostMessageW);
    //DETACH(LoadLibraryA);
    //DETACH(LoadLibraryW);
    //DETACH(LoadLibraryExA);
    DETACH(LoadLibraryExW);
    //DETACH(MultiByteToWideChar);
    DETACH(WideCharToMultiByte);

    //DETACH(RtlMultiByteToUnicodeN);
    //DETACH(RtlUnicodeToMultiByteN);

    DetourTransactionCommit();

    return S_OK;
}

VOID WINAPI CorelOutputDebugStringA(LPCSTR lpOutputString)
{
    if (GlobInit() && (NULL != g_pcAPIProxy))
    {
        g_pcAPIProxy->OutputDebugStringA(lpOutputString);
    }
    else
    {
        TrueOutputDebugStringA(lpOutputString);    
    }
}

VOID WINAPI CorelOutputDebugStringW(LPCWSTR lpOutputString)
{
    if (GlobInit() && (NULL != g_pcAPIProxy))
    {
        g_pcAPIProxy->OutputDebugStringW(lpOutputString);
    }
    else
    {
        TrueOutputDebugStringW(lpOutputString);    
    }
}

LRESULT WINAPI CorelSendMessageA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    LRESULT t_ret;
    if (GlobInit() && (NULL != g_pcAPIProxy))
    {
        t_ret = g_pcAPIProxy->SendMessageA(hWnd, Msg, wParam, lParam);
    }
    else
    {
        t_ret = TrueSendMessageA(hWnd, Msg, wParam, lParam);    
    }
    return t_ret;
}

LRESULT WINAPI CorelSendMessageW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    LRESULT t_ret;
    if (GlobInit() && (NULL != g_pcAPIProxy))
    {
        t_ret = g_pcAPIProxy->SendMessageW(hWnd, Msg, wParam, lParam);
    }
    else
    {
        t_ret = TrueSendMessageW(hWnd, Msg, wParam, lParam);    
    }
    return t_ret;
}

BOOL WINAPI CorelPostMessageA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    BOOL t_ret;
    if (GlobInit() && (NULL != g_pcAPIProxy))
    {
        t_ret = g_pcAPIProxy->PostMessageA(hWnd, Msg, wParam, lParam);
    }
    else
    {
        t_ret = TruePostMessageA(hWnd, Msg, wParam, lParam);    
    }
    return t_ret;
}

BOOL WINAPI CorelPostMessageW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    BOOL t_ret;
    if (GlobInit() && (NULL != g_pcAPIProxy))
    {
        t_ret = g_pcAPIProxy->PostMessageW(hWnd, Msg, wParam, lParam);
    }
    else
    {
        t_ret = TruePostMessageW(hWnd, Msg, wParam, lParam);    
    }
    return t_ret;
}

long WINAPI CorelBroadcastSystemMessageA(DWORD flags, LPDWORD lpInfo, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    long t_ret;
    if (GlobInit() && (NULL != g_pcAPIProxy))
    {
        t_ret = g_pcAPIProxy->BroadcastSystemMessageA(flags, lpInfo, Msg, wParam, lParam);
    }
    else
    {
        t_ret = TrueBroadcastSystemMessageA(flags, lpInfo, Msg, wParam, lParam);    
    }
    return t_ret;
}

long WINAPI CorelBroadcastSystemMessageW(DWORD flags, LPDWORD lpInfo, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    long t_ret;
    if (GlobInit() && (NULL != g_pcAPIProxy))
    {
        t_ret = g_pcAPIProxy->BroadcastSystemMessageW(flags, lpInfo, Msg, wParam, lParam);
    }
    else
    {
        t_ret = TrueBroadcastSystemMessageW(flags, lpInfo, Msg, wParam, lParam);    
    }
    return t_ret;
}

long WINAPI CorelBroadcastSystemMessageExA(DWORD flags,LPDWORD lpInfo, UINT Msg, WPARAM wParam, LPARAM lParam, PBSMINFO pbsmInfo)
{
    long t_ret;
    if (GlobInit() && (NULL != g_pcAPIProxy))
    {
        t_ret = g_pcAPIProxy->BroadcastSystemMessageExA(flags, lpInfo, Msg, wParam, lParam, pbsmInfo);
    }
    else
    {
        t_ret = TrueBroadcastSystemMessageExA(flags, lpInfo, Msg, wParam, lParam, pbsmInfo);    
    }
    return t_ret;
}

long WINAPI CorelBroadcastSystemMessageExW(DWORD flags,LPDWORD lpInfo, UINT Msg, WPARAM wParam, LPARAM lParam, PBSMINFO pbsmInfo)
{
    long t_ret;
    if (GlobInit() && (NULL != g_pcAPIProxy))
    {
        t_ret = g_pcAPIProxy->BroadcastSystemMessageExW(flags, lpInfo, Msg, wParam, lParam, pbsmInfo);
    }
    else
    {
        t_ret = TrueBroadcastSystemMessageExW(flags, lpInfo, Msg, wParam, lParam, pbsmInfo);    
    }
    return t_ret;
}

HMODULE WINAPI CorelLoadLibraryA(LPCSTR lpLibFileName)
{
    HMODULE t_ret;
    if (GlobInit() && (NULL != g_pcAPIProxy))
    {
        t_ret = g_pcAPIProxy->LoadLibraryA(lpLibFileName);
    }
    else
    {
        t_ret = TrueLoadLibraryA(lpLibFileName);
    }
    return t_ret;
}

HMODULE WINAPI CorelLoadLibraryW(LPCWSTR lpLibFileName)
{
    HMODULE t_ret;
    if (GlobInit() && (NULL != g_pcAPIProxy))
    {
        t_ret = g_pcAPIProxy->LoadLibraryW(lpLibFileName);
    }
    else
    {
        t_ret = TrueLoadLibraryW(lpLibFileName);
    }
    return t_ret;
}

HMODULE WINAPI CorelLoadLibraryExA(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
{
    HMODULE t_ret;
    if (GlobInit() && (NULL != g_pcAPIProxy))
    {
        t_ret = g_pcAPIProxy->LoadLibraryExA(lpLibFileName, hFile, dwFlags);
    }
    else
    {
        t_ret = TrueLoadLibraryExA(lpLibFileName, hFile, dwFlags);
    }
    return t_ret;
}

HMODULE WINAPI CorelLoadLibraryExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
{
    HMODULE t_ret;
    if (GlobInit() && (NULL != g_pcAPIProxy))
    {
        t_ret = g_pcAPIProxy->LoadLibraryExW(lpLibFileName, hFile, dwFlags);
    }
    else
    {
        t_ret = TrueLoadLibraryExW(lpLibFileName, hFile, dwFlags);
    }
    return t_ret;
}

int WINAPI CorelMultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte, LPWSTR lpWideCharStr, int cchWideChar)
{
    int t_ret;
    if (GlobInit() && (NULL != g_pcAPIProxy))
    {
        t_ret = g_pcAPIProxy->MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, lpWideCharStr, cchWideChar);
    }
    else
    {
        t_ret = TrueMultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, lpWideCharStr, cchWideChar);
    }
    return t_ret;
}

int WINAPI CorelWideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar)
{
    int t_ret;
    if (GlobInit() && (NULL != g_pcAPIProxy))
    {
        t_ret = g_pcAPIProxy->WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, lpMultiByteStr, cbMultiByte, lpDefaultChar, lpUsedDefaultChar);
    }
    else
    {
        t_ret = TrueWideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, lpMultiByteStr, cbMultiByte, lpDefaultChar, lpUsedDefaultChar);
    }
    return t_ret;
}

LONG WINAPI CorelRtlMultiByteToUnicodeN(PWCH UnicodeString, ULONG MaxBytesInUnicodeString, PULONG BytesInUnicodeString, const CHAR *MultiByteString, ULONG BytesInMultiByteString)
{
    LONG t_lRet;
    if (GlobInit() && (NULL != g_pcAPIProxy))
    {
        t_lRet = g_pcAPIProxy->RtlMultiByteToUnicodeN(UnicodeString, MaxBytesInUnicodeString, BytesInUnicodeString, MultiByteString, BytesInMultiByteString);
    }
    else
    {
        t_lRet = TrueRtlMultiByteToUnicodeN(UnicodeString, MaxBytesInUnicodeString, BytesInUnicodeString, MultiByteString, BytesInMultiByteString);
    }
    return t_lRet;
}

LONG WINAPI CorelRtlUnicodeToMultiByteN(PCHAR MultiByteString, ULONG MaxBytesInMultiByteString, PULONG BytesInMultiByteString, PCWCH UnicodeString, ULONG BytesInUnicodeString)
{
    LONG t_lRet;
    if (GlobInit() && (NULL != g_pcAPIProxy))
    {
        t_lRet = g_pcAPIProxy->RtlUnicodeToMultiByteN(MultiByteString, MaxBytesInMultiByteString, BytesInMultiByteString, UnicodeString, BytesInUnicodeString);
    }
    else
    {
        t_lRet = TrueRtlUnicodeToMultiByteN(MultiByteString, MaxBytesInMultiByteString, BytesInMultiByteString, UnicodeString, BytesInUnicodeString);
    }
    return t_lRet;
}
